/***********************************************************************************
  Copy right:     2020-2030 ESP8266 AP demo.
  Author:         hujianguo
  Date:           2022.6.19
  Description:    终端AP服务处理程序
***********************************************************************************/
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>

/**************** WIFI及默认配置 *****************/
const char *ssid = "apapapap";                //AP的SSID（WiFi名字）
const char *password = "12345678";            //AP的密码
int State_Connect = 0;                            //判断当前的链接是否正常，无连接时请求重连
IPAddress sta_client;                             //保存sta设备的ip地址

/**************** UDP设置项 *****************/
unsigned int read_Port = 11235;     //监听端口
unsigned int send_Port = 11234;     //发送端口
char readdata[512];                 //数据缓存
WiFiUDP Udp;                        //定义udp

IPAddress fs_sta_ip(192, 168, 2, 2);     //风扇控制的ip地址
IPAddress hqs_sta_ip(192, 168, 2, 3);     //换气扇控制的ip地址
IPAddress led_sta_ip(192, 168, 2, 4);     //led控制的ip地址

/**************** 串口设置项 *****************/
static String inputString = "";
static bool stringComplete = false;


//初始化AP信息，作为网络中心管理
void init_AP()
{
  WiFi.mode(WIFI_AP);                           //设置为AP模式
  WiFi.softAP(ssid, password);                //配置AP信息，并开启AP

  //默认IP为192.168.2.1 , 这里我自定义设置AP的ip段
  IPAddress softLocal(192, 168, 2, 1);        //IP地址，用以设置IP第4字段
  IPAddress softGateway(192, 168, 2, 1);      //IP网关，用以设置IP第3字段
  IPAddress softSubnet(255, 255, 255, 0);
  //配置自定义的IP信息
  WiFi.softAPConfig(softLocal, softGateway, softSubnet);
  IPAddress myIP = WiFi.softAPIP();           //用变量myIP接收AP当前的IP地址
  Serial.println("myIP的IP地址\r\n");
  Serial.println(myIP);                       //打印输出myIP的IP地址
}

/*自定义函数
  将接收的数据，以String类型返回，方便分析处理
*/
String Read_Udp()
{
  String data = "";
  int packetSize = Udp.parsePacket();
//  Serial.printf("packetSize = %d\r\n", packetSize);
  if (packetSize)
  {
    sta_client = Udp.remoteIP();
    memset(readdata, 0x00, sizeof(readdata));
    Udp.read(readdata, 511);
    Udp.flush();
    for (int i = 0; i < packetSize; i++)
    {
      data += readdata[i];
    }
//    Serial.println(data);
  }
  return data;
}

/*自定义函数
  封装数据发送功能，方便调用
  第一个参数，使用String类型作为发送内容
  第二个参数，a为真，指定发送，对发送方返回数据，a为假，以保存的ip发送数据
*/
void myPrint(String data, bool a)
{
  if (a)
  {
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
  }
  else
  {
    Udp.beginPacket(sta_client, send_Port);
  }
  Udp.print(data);
  Udp.endPacket();
}

/************自定义函数，对接收数据分析处理************/
void Udp_Handler(String data)
{
  if (data != "")
  {
    if (data == "opena_success")
    {
      //将返回值通过串口输出
      Serial.println(data);
    }
    else if (data == "closea_success")
    {
      //将返回值通过串口输出
      Serial.println(data);
    }
    else if (data == "openb_success")
    {
      //将返回值通过串口输出
      Serial.println(data);
    }
    else if (data == "closeb_success")
    {
      //将返回值通过串口输出
      Serial.println(data);
    }
    else if (data == "openc_success")
    {
      //将返回值通过串口输出
      Serial.println(data);
    }
    else if (data == "closec_success")
    {
      //将返回值通过串口输出
      Serial.println(data);
    }
    else
    {
      //将返回值通过串口输出
      Serial.printf("error");
    }
  }
}

//上电初始化工作区
void setup()
{
  //初始换串口
  Serial.begin(115200);
  Serial.println("");
  Serial.printf("***** 串口初始化完成 *****\r\n");
  //初始化wifi为ap模式
  init_AP();
  //UDP设置监听指定端口
  Udp.begin(read_Port);
}

//主循环工作区
void loop()
{
  //开启串口接收
  serialRx();

  int gotoAP = WiFi.softAPgetStationNum();  //获取当前连接到AP的设备数量
  if (gotoAP == 0)
  {
    //    Serial.printf("***** WiFi 无连接 *****\r\n");
    State_Connect = 0;  //wifi链接状态为断开
  }
  else if (gotoAP > 0)
  {
    //    Serial.printf("***** WiFi连接成功 *****\r\n");
    State_Connect = 1;  //wifi链接状态为链接
    Udp_Handler(Read_Udp());
  }
  else
  {
    State_Connect = 2;  //wifi正在连接中
  }
}

//串口接收处理函数，主要接收来自主控的控制指令
void serialRx()
{
  int ret = 0;
  if (Serial.available())
  {
    // get the new byte:
    char inChar = (char)Serial.read();
    // add it to the inputString:
    inputString += inChar;
    // if the incoming character is a newline, set a flag so the main loop can
    // do something about it:
    if (inChar == '\n')
    {
      stringComplete = true;
    }
  }
  //打印接收到的串口数据
  if (stringComplete)
  {
    //查询当前连接的sta数量
    if (inputString == "sta_num\n")
    {
      //获取当前连接到AP的设备数量
      int AP_num = WiFi.softAPgetStationNum();
      Serial.println(AP_num );
      inputString = "";

      stringComplete = false;
    }
    //打开风扇
    else if (inputString == "open_a\n")
    {
      Udp.beginPacket(fs_sta_ip, send_Port);
      Udp.print(inputString);
      Udp.endPacket();

      inputString = "";

      stringComplete = false;
    }
    //关闭风扇
    else if (inputString == "close_a\n")
    {
      Udp.beginPacket(fs_sta_ip, send_Port);
      Udp.print(inputString);
      Udp.endPacket();

      inputString = "";

      stringComplete = false;
    }
    //打开换气扇
    else if (inputString == "open_b\n")
    {
      Udp.beginPacket(hqs_sta_ip, send_Port);
      Udp.print(inputString);
      Udp.endPacket();

      inputString = "";

      stringComplete = false;
    }
    //关闭换气扇
    else if (inputString == "close_b\n")
    {
      Udp.beginPacket(hqs_sta_ip, send_Port);
      Udp.print(inputString);
      Udp.endPacket();

      inputString = "";

      stringComplete = false;
    }
    //打开灯光
    else if (inputString == "open_c\n")
    {
      Udp.beginPacket(led_sta_ip, send_Port);
      Udp.print(inputString);
      Udp.endPacket();

      inputString = "";

      stringComplete = false;
    }
    //关闭灯光
    else if (inputString == "close_c\n")
    {
      Udp.beginPacket(led_sta_ip, send_Port);
      Udp.print(inputString);
      Udp.endPacket();

      inputString = "";

      stringComplete = false;
    }
    //打开氛围灯
    else if (inputString == "open_f\n")
    {
      Udp.beginPacket(led_sta_ip, send_Port);
      Udp.print(inputString);
      Udp.endPacket();

      inputString = "";

      stringComplete = false;
    }
    //关闭氛围灯
    else if (inputString == "close_f\n")
    {
      Udp.beginPacket(led_sta_ip, send_Port);
      Udp.print(inputString);
      Udp.endPacket();

      inputString = "";

      stringComplete = false;
    }
    else
    {
      //没有此操作，不需要处理，只返回错误
      Serial.println(ret);
    }
  }
}
